package com.example.demo.http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.StampedLock;


/**
 * User: wcy
 * Date: 2017/11/22
 * Time: 16:30
 */

public class RestClientTemplate<T> {
    private static final StampedLock initLock = new StampedLock();

    private static PoolingHttpClientConnectionManager phccm;

    private static String UTF_8 = "UTF-8";

    private static final String ERROR_MSG = "{\"errCode\":\"8500\"}";

    private static int isAngela = 0;

    private static final RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(5000).build();

    private static void init() {
        long stamp = initLock.writeLock();
        try {
            if (phccm == null) {
                phccm = new PoolingHttpClientConnectionManager();
                phccm.setMaxTotal(50);// 整个连接池最大连接数
                phccm.setDefaultMaxPerRoute(5);// 每路由最大连接数，默认值是2
            }
        } finally {

            initLock.unlock(stamp);
        }
    }

    private static CloseableHttpClient getClient() {
        init();
        return HttpClients.custom().setConnectionManager(phccm).build();
    }

    public static void main(String args[]) {

        String url = "http://uctenant.drore.com/sso/getRightMenuRecursion.htm?token=v10WK9B625dVwRueGlN1259crdGHTZqS2Q0R3CRdOZm9EVs5Wld8AXXzu3YiBbdAg1VobSUBbVhE%0AcDzj2s1k%2BIt6EwpKqVEwrydMferRPFTyoXOLjhpmOB7QWtzk0zMCZG5UcgTz8bzTEiN%2BXznysjKo%0A%2FzpnLIUqFUCfvbjT8%2BY%3D&sysNum=gis";
        JSONObject obj = new JSONObject();
        obj.put("a", 1);
        String a = "{\"errCode\":\"8501\"}";
        String b = "sd";
        Map map = new HashMap();
        map.put("id", "abc");
        map.put("id1", "abc");
        map.put("id1", "abc");
        List list = new ArrayList();
        list.add(1);
        RestClientTemplate aa = new RestClientTemplate();
        System.out.println(map);
        //Object d = aa.doGetRequestAddHeader(url, obj, map);
        Object d = aa.doPost(url, map);
        System.out.println(d.getClass().getName());

    }


    //通用的请求方式
    private T currencyRequest(String url, T requestDataMessage, T params) {
        //去请求
        T requestDataResult = (T) doDynameic(requestDataMessage, url, params);
        System.out.println(requestDataResult);
        return (T) requestDataResult;
    }

    public T doPost(String url, T params) {
        return currencyRequest(url, params, params);
    }

    public T doPut(String url, T params) {
        return currencyRequest(url, params, params);
    }

    public T doDelete(String url, T params) {
        return currencyRequest(url, params, params);
    }

    public T doPatch(String url, T params) {
        return currencyRequest(url, params, params);
    }

    public T doGetRequest(String url, T params) {
        return currencyRequest(url, params, params);
    }


    public T doGetRequestAddHeader(String url, JSONObject headers, T params) {
        //排除不合法请求类型
        JSONObject jsonObject = null;
        if (null != params && !"".equals(params)) {
            try {
                jsonObject = JSON.parseObject(jsonObject.toJSONString(params));
                jsonObject.put("headers", headers);
            } catch (JSONException e) {
                e.printStackTrace();
                return (T) JSONObject.parseObject("{\"errCode\":\"8500\",\"errMessage\":\"数据不合法\"}", params.getClass());
            } finally {
                //  head添加进去访问共有类，因为此处对泛型T进行了类型赋值，所以得有两个params
                return currencyRequest(url, (T) jsonObject, params);
            }
        } else {
            //此处返回null，因为泛型T.getClass会报错
            return null;
        }
    }

    public T postForm(String url, T params) {
        return currencyRequest(url, params, params);
    }


    protected ArrayList<NameValuePair> covertParams2NVPS(JSONObject params) {

        ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();

        for (Map.Entry<String, Object> param : params.entrySet()) {
            pairs.add(new BasicNameValuePair(param.getKey(), String.valueOf(param.getValue())));
        }
        return pairs;
    }


    public String doGet(String url) {
        try {
            URL formatUrl = new URL(url);
            URI uri = new URI(formatUrl.getProtocol(), (formatUrl.getHost() +
                    (formatUrl.getPort() == -1 ? "" : ":" + formatUrl.getPort())),
                    formatUrl.getPath(), formatUrl.getQuery(), null);
            HttpGet httpGet = new HttpGet(uri);
            return getResult(httpGet, null);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return ERROR_MSG;
    }

    public String doGetNotEncoding(String url) {
        HttpGet httpGet = new HttpGet(url);
        return getResult(httpGet, null);
    }

    public String doPost(String url) {
        HttpPost httpPost = new HttpPost(url);
        return getResult(httpPost, null);
    }

    public String doPut(String url) {
        HttpPut httpPut = new HttpPut(url);
        return getResult(httpPut, null);
    }

    public String doDelete(String url) {
        HttpDelete httpDelete = new HttpDelete(url);
        return getResult(httpDelete, null);
    }

    public String doPatch(String url) {
        HttpPatch httpPatch = new HttpPatch(url);
        return getResult(httpPatch, null);
    }


    protected String getResult(HttpRequestBase request, JSONObject params) {
        //添加日志状态
        AngelaLoggerEntity logger = getLogger(request, params);
        long startTime = System.currentTimeMillis();
        CloseableHttpClient httpClient = getClient();

        CloseableHttpResponse response = null;
        try {
            //请求参数设置
            request.setConfig(requestConfig);
            //请求参数添加请求头
            request = addChainNodeToRequest(request);
            response = httpClient.execute(request);
            //添加日志状态
            logger.setStatus(response.getStatusLine().getStatusCode() + "");
            //添加日志状态
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity);
                    //添加日志信息
                    logger.setResult(result);
                    return result;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                long endTime = System.currentTimeMillis();
                logger.setElapsedTime(endTime - startTime);
                AngelaAopLogger.loggerHttpClient(logger);
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return ERROR_MSG;
    }

    public static HttpRequestBase addChainNodeToRequest(HttpRequestBase request) {
        String uuid = UUIDGenerator.getUuid();
        request.addHeader(AdapterHttpHeaders.RootId.getName(), LoggerThreadLocal.getLoggerId());
        request.addHeader(AdapterHttpHeaders.NodeId.getName(), uuid);
        request.addHeader(AdapterHttpHeaders.ParentNodeId.getName(), LoggerThreadLocal.getNodeLoggerId());
        LoggerThreadLocal.setNodeId(uuid);
        return request;
    }

    private static AngelaLoggerEntity getLogger(HttpRequestBase request, JSONObject params) {
        AngelaLoggerEntity logger = new AngelaLoggerEntity();
        logger.setParentNode(LoggerThreadLocal.getLoggerId());
        logger.setInterfaceName(request.getURI().getPath());
        logger.setSourcrfaceIp(request.getURI().toString());
        logger.setInterfacePort(request.getURI().getPort());
        logger.setParms(JSON.toJSONString(params));
        return logger;
    }

    //做保护，用来做最后发送请求的准备
    private T doDynameic(T obj, String url, T params) {
        //处理结果
        Object resultFinaly = null;
        if (null != obj && !"".equals(obj)) {
            JSONObject jsonObject = JSON.parseObject(JSONObject.toJSONString(obj));
            try {
                //此处执行访问，得打返回结果result
                String result = returnDataRequest(url, jsonObject);
                //处理最终返回结果
                resultFinaly = JSON.parseObject(result, params.getClass());
            } catch (JSONException e) {
                e.printStackTrace();
                return (T) JSONObject.parseObject("{\"errCode\":\"8500\",\"errMessage\":\"数据不合法\"}", params.getClass());
            } finally {
                //错误信息处理
                return (T) resultFinaly;
            }
        } else {
            //打印日志，并返回参数，
            return null;
        }
    }


    //发送请求
    public static String returnDataRequest(String url, JSONObject jSONObject) {
        String method = Thread.currentThread().getStackTrace()[4].getMethodName();
        //调用泛型必须实例化
        RestClientTemplate restClientTemplate = new RestClientTemplate();
        String result;

        URIBuilder ub = new URIBuilder();
        ArrayList<NameValuePair> pairs = restClientTemplate.covertParams2NVPS(jSONObject);
        //此处用switch，性能比if高
        switch (method) {
            case "doGetRequest":
                ub.setPath(url);
                ub.setParameters(pairs);
                HttpGet httpGet;
                try {
                    httpGet = new HttpGet(ub.build());
                } catch (URISyntaxException e) {
                    e.printStackTrace();
                    return "{\"errCode\":\"8500\"}";
                }
                result = restClientTemplate.getResult(httpGet, null);
                break;
            case "doGetRequestAddHeader":
                ub.setPath(url);
                ub.setParameters(pairs);
                try {
                    httpGet = new HttpGet(ub.build());
                } catch (URISyntaxException e) {
                    e.printStackTrace();
                    return "{\"errCode\":\"8500\"}";
                }
                JSONObject headers = (JSONObject) jSONObject.get("headers");
                for (Map.Entry<String, Object> param : headers.entrySet()) {
                    httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));
                }
                result = restClientTemplate.getResult(httpGet, jSONObject);
                break;
            case "doPut":
                HttpPut httpCurrency = new HttpPut(url);
                result = restClientTemplate.getResult(httpCurrency, jSONObject);
                break;
            case "doPost":
                HttpPost httpPost = new HttpPost(url);
                httpPost.setHeader("Content-Type", "application/json");
                httpPost.setEntity(new StringEntity(jSONObject.toJSONString(), "UTF-8"));
                result = restClientTemplate.getResult(httpPost, jSONObject);
                break;
            case "postForm":
                url = StringUtils.trimToEmpty(url);
                HttpPost postForm = new HttpPost(url);
                postForm.setHeader("Content-Type", "application/x-www-form-urlencoded");
                try {
                    postForm.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    return "{\"errCode\":\"8500\"}";
                }
                result = restClientTemplate.getResult(postForm, jSONObject);
                break;
            case "doPatch":
                HttpPatch httpPatch = new HttpPatch(url);
                result = restClientTemplate.getResult(httpPatch, jSONObject);
                break;
            case "doDelete":
                HttpDelete httpDelete = new HttpDelete(url);
                result = restClientTemplate.getResult(httpDelete, jSONObject);
                break;
            case "HEADER":
                //HEAD就像GET，只不过服务端接受到HEAD请求后只返回响应头，而不会发送响应内容。当我们只需要查看某个页面的状态的时候,
                // 使用HEAD是非常高效的，因为在传输的过程中省去了页面内容。
                HttpHead httpHead = new HttpHead(url);
                httpHead.addHeader("Accept", "text/html");
                result = restClientTemplate.getResult(httpHead, jSONObject);
                break;
            case "OPTIONS":
                HttpOptions httpOptions = new HttpOptions(url);
                result = restClientTemplate.getResult(httpOptions, jSONObject);
                break;
            case "TRACE":
                HttpTrace httpTrace = new HttpTrace(url);
                result = restClientTemplate.getResult(httpTrace, jSONObject);
                break;
            default:
                return "{\"errCode\":\"8500\",\"errMessage\":\"非法访问!\"}";
        }
        return result;
    }
}
